package Tools;

import java.util.ArrayList;

import pyrachnid.ctrl.Simulator;
import pyrachnid.model.ground_model.Map;
import pyrachnid.model.ground_model.Wind;
import pyrachnid.model.ground_model.Wind.Direction;
import pyrachnid.model.pathFinderModel.Astar;
import pyrachnid.model.pathFinderModel.PathFind;
import pyrachnid.model.pathFinderModel.PathFind.PathFindEnum;
import pyrachnid.model.robot_model.Robot;
import pyrachnid.model.robot_model.RobotType;
import pyrachnid.model.scenar_model.Scenario;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

/**
 * @author zygou
 *
 */
public class ScenarConverterXML implements Converter {	
	
	private Simulator _simulator;
	private Scenario _scenar;
	
	public ScenarConverterXML(XStream xstream, Simulator pSim){
		super();
		_simulator = pSim;
		xstream.alias("Scenario", Scenario.class);
		_scenar = new Scenario(_simulator);
		xstream.registerConverter(new MapConverterXML(xstream, _scenar));
	}
	
	@SuppressWarnings("rawtypes")
	@Override
	public boolean canConvert(Class scenarClass) {
		return scenarClass.equals(Scenario.class);
	}

	@Override
	public void marshal(Object scenarObject, HierarchicalStreamWriter writer,
			MarshallingContext context) {
		
		// cast scenar object
		this._scenar = (Scenario) scenarObject;
		
		// write attributes
		writer.addAttribute("name", _scenar.getName());
		writer.addAttribute("duration", String.valueOf(_scenar.getDuration()));
		writer.addAttribute("speed", String.valueOf(_scenar.getSpeed()));
		// write nodes
		writer.startNode("MapPath");
			writer.setValue(_scenar.getMapPath());
		writer.endNode();
		
		writer.startNode("Wind");
			writer.addAttribute("direction", _scenar.getWind().getDirection().toString());
			writer.addAttribute("force", String.valueOf(_scenar.getWind().getForce()));
		writer.endNode();
		
		writer.startNode("Map");
			context.convertAnother(_scenar.getMap());
		writer.endNode();
		
		writer.startNode("Robot-Types");
		for(RobotType robotType : _scenar.getRobotTypeList()){
			writer.startNode("Robot-Type");
				writer.addAttribute("name", robotType.toString());
				
				writer.startNode("maxGroundValue");
					writer.setValue(String.valueOf(robotType.getMaxGroundValue()));
				writer.endNode();
				
				writer.startNode("maxGroundSpeed");
					writer.setValue(String.valueOf(robotType.getGroundInfluence()));
				writer.endNode();
				
				writer.startNode("extinguishingSpeed");
					writer.setValue(String.valueOf(robotType.getExtinguishingSpeed()));
				writer.endNode();
				
				writer.startNode("pathFinder");
					writer.setValue(robotType.getPathFind().toString());
				writer.endNode();
				
				writer.startNode("image");
					writer.setValue(robotType.getImagePath());
				writer.endNode();
			writer.endNode();
		}
		writer.endNode();
		
		writer.startNode("Robots");
		for(Robot robot : _scenar.getRobotList()){
			writer.startNode("Robot");
				writer.addAttribute("x", String.valueOf(robot.getPositionX()));
				writer.addAttribute("y", String.valueOf(robot.getPositionY()));
				
				writer.startNode("Robot-Type");
					writer.addAttribute("name", robot.getRobotType().toString());
				writer.endNode();
			writer.endNode();
		}
		writer.endNode();
	}

	@Override
	public Object unmarshal(HierarchicalStreamReader reader,
			UnmarshallingContext context) {
		
		_scenar.setName(reader.getAttribute("name"));
		_scenar.setDuration(Integer.valueOf(reader.getAttribute("duration")));
		_scenar.setSpeed(Integer.valueOf(reader.getAttribute("speed")));
		
		//get back map Path
		reader.moveDown();
			_scenar.setMapPath(reader.getValue());
		reader.moveUp();
		
		//get back wind attribute
		reader.moveDown();
		int windForce = Integer.valueOf(reader.getAttribute("force"));
		String strDir = reader.getAttribute("direction");
			for(Direction dir : Wind.Direction.values()){
				if(dir.getDirection().equals(strDir))
					_scenar.setWind(new Wind(dir,windForce));
			}
		reader.moveUp();
		
		//get back the map
		reader.moveDown();
			context.convertAnother(_scenar, Map.class);
		reader.moveUp();
			
		//getBack Robot-Types
		reader.moveDown();
			while(reader.hasMoreChildren()){
				reader.moveDown();
					String rtName= reader.getAttribute("name");
					
					reader.moveDown();
						int maxGroundval = Integer.valueOf(reader.getValue());
					reader.moveUp();
					
					reader.moveDown();
						double maxGroundSpeed = Double.valueOf(reader.getValue());
					reader.moveUp();
						
					reader.moveDown();
						double extinguishingSpeed = Double.valueOf(reader.getValue());
					reader.moveUp();
					
					reader.moveDown();
					PathFind pf = new Astar();
					
					for(PathFindEnum pathFindEnum : PathFindEnum.values()){
						if(reader.getValue().equals(pathFindEnum.getPathFind().toString()))
							pf= pathFindEnum.getPathFind();
					}
					
					reader.moveUp();
					
					reader.moveDown();
						String pathImage = reader.getValue(); 
					reader.moveUp();
					
					_scenar.addRobotType(new RobotType(rtName, maxGroundval, maxGroundSpeed, extinguishingSpeed, pf, pathImage));
				reader.moveUp();
			}
		reader.moveUp();
		
		//getBack Robots
		reader.moveDown();
			while(reader.hasMoreChildren()){
				reader.moveDown();
					int posX = Integer.valueOf(reader.getAttribute("x"));
					int posY = Integer.valueOf(reader.getAttribute("y"));
					reader.moveDown();
						for(RobotType rt : _scenar.getRobotTypeList()){
							if(rt.getNameType().equals(reader.getAttribute("name"))){
								ArrayList<Robot> toto = _scenar.getRobotList();
								toto.add(new Robot(posX, posY, rt));
							}
						}
					reader.moveUp();
				reader.moveUp();
			}
		reader.moveUp();
		return _scenar;
	}
}